044-UART. Применение в электронных проектах.
Раз уж я буду использовать UART для связки устройств блога с Вашими проектами немного расскажу как он устроен и как им пользоваться.
Универсальный асинхронный приемопередатчик (UART) довольно старый и распространенный интерфейс. До недавнего времени разъем COM порта (тот-же UART только уровни напряжения другие) был обязательным атрибутом каждого компьютера. Теперь COM порт постепенно «отмирает» и если на «башнях» он еще не редкость, то на ноутбуках его уже нет и в помине. Но в виду простоты и популярности интерфейса подавляющее большинство микроконтроллеров имеет UART в составе своей периферии. И если персональный компьютер UART перестает удовлетворять из-за низкой скорости и невозможности расширения, то для микроконтроллеров интерфейс удобен и использование его будет продолжаться.
Раз UART есть во многих микроконтроллерах, значит мы его будем использовать как один из интерфейсов связи устройств блога с Вашими электронными устройствами.
Для начала немного теории работы интерфейса (без лишних подробностей). Для связи по интерфейсу UART используется две ножки контроллера RXD – для приема сообщений (Receiver) и TXD – для передачи сообщений (Transmitter). UART – полнодуплексный интерфейс. Это значит, что приемник и передатчик работают независимо друг от друга. Более того, передатчик или приемник можно отдельно отключить, освободив ножку контроллера для других нужд. Передача (соответственно и прием) сообщений осуществляется фиксированными пакетами битов (такой пакет называют кадром). Кадр состоит из старт-бита (с него начинается каждый кадр), битов данных (может быть от 5 до 9 бит), бита проверки четности (проверка правильности передачи данных) и одного или двух стоп-битов (сигнал об окончании кадра).
где:
IDLE – ожидание обмена – должна быть 1;
St – Старт-бит – всегда 0;
(n) - Биты данных – может быть от 5 до 9 бит;
P – Бит четности;
Sp – Стоп бит – всегда 1.
Если посылка содержит более одного байта, каждый следующий байт передается отдельным кадром. Передача (и прием) данных ведется на определенных фиксированных частотах (измеряется в Бод=бит/сек) от 600 до 128 000 Бод. Условием правильной работы порта есть задание одинаковых параметров, как для приемника, так и для передатчика (скорость, количество бит данных, бит четности, количество стоп битов).
Договоримся о формате кадра (настройках UART) для устройств блога:
Скорость передачи – 9600 (это в пределах килобайта в секунду);
Количество бит данных – 8 (наиболее удобно работать);
Бит четности – Even (производится проверка на четность);
Количество стоп-бит – 1;
В сокращенном варианте это выглядит так:
Baud Rate: 9600, 8 Data, 1 Stop, Even Parity
Еще UART может работать в синхронном режиме (для этого задействуется еще одна ножка контроллера) и поддерживать адресацию множества устройств. Но так как наши устройства несложны и нам не нужны данные функции, то рассматривать мы их не будем.
Если нужны дополнительные возможности, то полное описание UART есть в datasheet на микроконтроллер – обращайтесь к нему.
Для того чтобы устройство с блога начало работать с Вашим проектом через интерфейс UART нужно:
1 Подключить устройство блога к соответствующим ножкам микроконтроллера.
2 Настроить приемо-передатчик UART Вашего контроллера. Для этого в соответствующие порта ввода/вывода записать определенные значения.
3 Иметь (написать) процедуры приема/передачи сообщений по UART в Вашей программе.
Теперь рассмотрим подробно каждый пункт:
1 СОЕДИНЕНИЕ УСТРОЙСТВ ПОСРЕДСТВОМ UART.
Тут все просто:
– если планируется и прием и передача – устройства соединяются по двум линиям – TX_устройства с RX_проекта и TX _проекта с RX_устройства (здесь и далее под «устройством» я буду понимать устройство с блога, а под «проектом» – Ваш электронный проект);
– если нужен только прием (например принимаются данные с клавиатуры) – TX_устройства с RX_проекта;
– если нужна только передача (например передаются данные на устройство отображения) – TX _проекта с RX_устройства.
2 НАСТРОЙКА ПРИЕМО-ПЕРЕДАТЧИКА UART.
Как мы договорились выше, формат кадра для наших устройств:
Baud Rate: 9600, 8 Data, 1 Stop, Even Parity
Для работы в с этим форматом кадра нужно в разделе инициализации устройств в Вашей программе, записать соответствующие значения в нужные порта ввода/вывода контроллера. Для этого нужно открыть раздел USART datasheet’а на Ваш микроконтроллер и выбрать/вычислить необходимые значения. Но можно сделать все гораздо проще – использовать автоматические настройщики периферии – CodeWisard’ы.
Возьмем для примера микроконтроллер Attiny2313 (по аналогии можно настроить любой микроконтроллер) и настроим UART в разных языках программирования.
Для начала – Algorithm Builder.
Тут все предельно просто – создаем проект (Файл/Новый). Выбираем микроконтроллер и частоту задающего генератора в Опции/Опции проекта… (ATtiny2313, внутренний задающий генератор на 8МГц). В панели инструментов жмем кнопочку «S» – настройщик управляющих регистров» выбираем USART и в открывшемся окошке заполняем все как на картинке. Там все подписано и понятно.
Жмем «ОК». Готово – UART проинициализирован и готов к работе.
Если нужен только приемник или только передатчик ставим только нужную галочку – незадействованную ножку можно использовать как порт ввода-вывода.
Так как в программе будут разрешены прерывания, нужно перед инициализацией USART установить указатель стека на конец памяти («S»/Stack Pointer SP) и озаглавить вершину блока ключевым словом «Reset».
В ассемблере. Честно говоря, я не знаю, есть ли в асемблерах для AVR настройщики периферии, но даже если нет, простое решение использовать все тот же Algorithm Builder. В окошке настройки USART, в правой части, прописаны мнемокоманды (Operations), обеспечивающие выбранные характеристики. Перевести их в ассемблерный код не составит труда.
Переводим в ассемблерные команды.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 | ;USART initialization ;Communication Parameters: 8 Data, 1 Stop, Even Parity ;USART Receiver: On ;USART Transmitter: On ;USART Mode: Asynchronous ;USART Baud Rate: 9600 uart_init: LDI R16, $00 OUT UBRRH,R16 LDI R16, $33 OUT UBRRL,R16 LDI R16,$26 OUT UCSRC, R16 LDI R16,$00 OUT UCSRA, R16 LDI R16,$98 OUT UCSRB, R16 |
Готово!
С – в программе CodeVisionAVR. CodeVision содержит свой настройщик периферии (CodeWisard), еще похлеще чем у Algorithm Builder’а. Для генерации настроек UART, нажимаем на значок шестеренку (CodeWisardAVR) на панели инструментов. В открывшемся окошке сначала выбираем вкладку Chip в ней выбираем микроконтроллер и устанавливаем частоту, с которой будет работать задающий генератор. Далее выбираем и заполняем вкладку USART в соответствии с нужными характеристиками (если нужен только приемник или только передатчик ставим соответствующую галочку).
1 2 3 4 5 6 7 8 9 10 11 12 13 | // USART initialization // Communication Parameters: // 8 Data, 1 Stop, Even Parity // USART Receiver: On // USART Transmitter: On // USART Mode: Asynchronous // USART Baud Rate: 9600 UCSRA=0x00; UCSRB=0x98; UCSRC=0x26; UBRRH=0x00; UBRRL=0x33; |
Сохраняем сгенерированный проект (File\Generate, Save and Exit) – готово. Создан проект со всеми нужными установками для UART. В проекте инициализируется и другая периферия (зачастую не нужная). После создания проекта его можно подкорректировать – удалить все не нужное.
3 СОЗДАНИЕ ПРОЦЕДУР ОБРАБОТКИ СООБЩЕНИЙ UART.
Небольшое отступление.
Работу с UART можно организовать различными способами. Например:
– просто ожидать в теле программы когда придет сообщение, постоянно проверяя бит приема сообщения;
– разрешить прерывание и в теле прерывания обрабатывать сообщение;
– создать буфер куда по прерываниям будут загоняться сообщения, а уже в теле программы, «по свободе», считывать из буфера значения;
– еще куча вариантов – выбор за Вами.
Но, исходя из того, что сообщения от устройств, в большинстве своем, единичные (один байт) и не слишком часты (взять, к примеру, клавиатуру – пару нажатий в секунду, не больше), наилучшим вариантом, в плане экономии памяти и скорости обработки, будет обработка сообщения UART в теле прерывания. Под обработкой я понимаю чтение регистров, проверка на правильность приема и сохранение принятого байта в глобальной переменной (своего рода буфер в один байт). Если предполагаются несложные манипуляции с принятым байтом можно их тоже организовать в теле прерывания.В дальнейшем я буду ориентироваться на такой алгоритм работы, если другой не будет более оправданным.
Algorithm Builder.
Прием данных осуществляется в процедуре обработки прерывания по окончании приема байта (кадра). Принятый байт записывается в глобальную переменную FromGCnDevice. В теле программы проверяется значение FromGCnDevice ели оно нулевое ничего не принято.
Если работа с принятым значением несложна можно это сделать прямо в теле обработки прерывания.
Передача данных производиться без использования прерываний и буфера (аппаратно у UART передатчика существует буфер на 2 байта). Это значит, что комфортно будут передаваться только единичные байты (что мы и планируем делать). Если зарядить сразу строку данных, то микроконтроллер будет заниматься только этой строкой.
Ассемблер.
Прием байта осуществляется в прерывании, результат остается в регистре r17 (если нужно сохраните в SRAM).
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 | ;Обработка прерывания по окончании приема байта PUSH R16 IN R16,SREG PUSH R16 IN R16,UCSRA ;Читаем статус из UCSRA IN R17,UDR ;Читаем данные из UDR ANDI R16,$1C BREQ _END ;Проверяем на ошибки CLR R17 _END: ;в R17 находится принятый байт POP R16 OUT SREG,R16 POP R16 RETI |
Передача байта
1 2 3 4 | LDI R16,значение SBIS UCSRA,UDRE RJMP PC-1 ; ждем готовности принять байт OUT UDR, R16 ; шлем байт |
С – в программе CodeVisionAVR.
Тут все просто CodeWizard вместе с инициализацией UART создает и процедуры для приема-передачи. Единственно что можно тут поковырять так это выкинуть буфер для приема (если разрешить прерывания по приему или передаче автоматически создается буфер). Если этот буфер не нужен процедура обработки прерывания приема байта и процедура передачи могут выглядеть так:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 | // Глобальная переменная - полученные даные от устройства // Эсли FromGCnDevice==0 - ничего не получено char FromGCnDevice; // Обработка прерывания окончания приема байта interrupt [USART_RXC] void usart_rx_isr(void) { char status; // Получаем байт статуса и данных status=UCSRA; FromGCnDevice=UDR; // Если произошла ошибка при приеме байта то FromGCnDevice=0 if ((status & (FRAMING_ERROR | PARITY_ERROR | DATA_OVERRUN))!=0)FromGCnDevice=0; } // Процедура передачи байта void ToGCnDevice (char c) { // Ждем окончания передачи предідущего байта while ((UCSRA & DATA_REGISTER_EMPTY)==0); // Передаем байт UDR=c; } |
Во и все про UART. Этого должно хватить для того чтобы подключить устройство к Вашему проекту. По анологии приведенных примеров легко все можно проделать и для других микроконтроллеров АВР.
Ниже оставляю архивы программ с примерами работы UART для ATtiny2313.
044-UART-CWAVR.zip [7.82 KB] - Пример проекта созданного автоматически CodeWisionsAVR
044-UART-AB.zip [5.11 KB] - Пример программы для работы с UART в Algorithm Builder
P.S. Я слабо знаю С и Asm, поэтому пинать и кидать тапками – разрешается! Мы все учимся.
Инициализируется
Baud Rate Error : 0.2 % ( CodeVisionAVR ) – значит стоял не UART-овский
кварц .
Receiver Buffer : 8 ( CodeVisionAVR ) – если на МК посылается сразу
более 8 байт , то могут быть ошибки , придется увеличивать размер буфера .
С интересом ждем про SPI и 1-Wire !
Да Baud Rate Error : 0.2 % – это погрешность(уход) частоты UART при использовании текущего задающего генератора (выбран внутренний генератор на 8МГц). Ставить специально для UART кварц не имеет смысла – только ножки потратишь (для UART допускается уход частоты до 10%).
Receiver Buffer : 8 – можно конечно и увеличить, но память (SRAM) у микроконтроллера не безграничная. Кроме того скорость передачи относительно низкая – микроконтроллер должен успевать «переваривать» принятые байты до переполнения буфера.
(При переполнении буфера ничего страшного не произойдет: установится переменная-флаг переполнения rx_buffer_overflow и дальше пойдет запись в буфер поверх не прочитанных данных)
Про SPI следующий пост, а про 1-Wire пока повременю.
Прошу помощи в коде C, представленном в статье.
Что это за оператор & ???
Я правильно понял что для передачи байта необходимо использовать процедуру ToGCnDevice? а для приема что использовать?
Заранее спасибо за ответ)
@plaza
упс парсер съел… имел ввиду & amp ;
Давно писал – уже и не помню. Походу это маска управляющих бит регистра UCSRA.
Здравствуйте, у меня вопрос, можно использовать этот конвертер для использования с Arduino, то есть я могу общаться с ПК через HyperTerminal? Это замена конвертера FTDI? Я слышал, что этот чип может быть подключен между устройствами (RX и TX).
Я планировал сделать клон Arduino, USB программатор я уже сделал, но не хватает общения в реальном времени
Я прошу прощения за русский, я из Молдовы.
Вы, наверное, немного не туда написали вопрос. Но если Вы имеете в виду соединение микроконтроллеров между собой, то это возможно.
может быть я не ясно выразился. даваите по ступениками, и по проще. У меня контроллер, и ПК. И я тупо в хипертерминале хочу увидеть значение АЦП (разумеется, с положеным для этого кода). Грубо говоря, хочу зделать аналог FTDI кабеля. (в буржуиском литературе он хорошо описавается, но мне не достать мах232 микруху, и такое решение как у вас не увидел ещё). Вопрос, этот преобазаватель, будет замена коневртера(USB-TTL)? дело в том что я не разобрался с уровням RS232, и уровни TTL, что привело мне в заблуждение.
Вот Вам преобразователь UART to USB http://www.getchip.net/posts/055-uart-to-usb-prostojj-preobrazovatel-na-attiny2313-versiya-2/
Это Вам полностью заменит FTDI.
@GetChiper
Большое спосибо, за ответ. Там очень ясно всё описоно, это я не старался искать, гыы… Прочитал почти весь саит, очень приятно собирать что-то уже собраное в практике, надежда что заработает вырастает. Так держать!
Очень интересная статья, а как к примеру из МК ATMEGA32 через UART можно EEPROM считаь и записать-? (к примеру нужно константы там менять).
Нужна программа внутри меги.
Если нужно просто посмотреть/поменять содержимое EEPROM проще считать программатором эту область с МК, посмотреть/подкорректировать и записать назад. Тот-же юнипроф http://www.getchip.net/posts/025-uniprof-universalnyjj-programmator-dlya-avr/ может прямо в окне показать содержимое EEPROM
Просто посмотреть меня не устраивает (можно просто PonyProg запустить и считаь только еепром), передо мной стоит задача минимум из командной строки считывать и записывать константы в определенные ячейки еепром. А в перспективе написать оболочку (например на Делфи)для быстрого перепрограммирования этих констант.И вот как это все в комплексе увязать не соображу.
в си и асм не силен, но других научу – настоящий педагогог!
подскажи, а usart и uart – одно и то же? в codevision (он все же vision!) идет инициализация портов и таймеров – это просто для порядка, в нашем случае не используется?
первые строчки define вообще непонятны – буду курить даташит по 2313
что значит иф за решеткой? (про RX_BUFFER_SIZE)
а как правильно отправлять сразу строчку, скажем, из 10 ascii символов?
для отправки байта достаточно в основном цикле делать put(byte)?
USART и UART одно и тоже.
#define PI 3.14 это опредиление означает что теперь в тексте программы ты можеш писать так B=A*PI; вместо B=A*3.14;. Это макрос для сокращения печатного текста или удобства.#if #else #endif #ifdef #ifndef тоже самое но для акробатики с опредилениями
))) Это часть языка си и искать инфу надо в самаучителе по си а не в даташите на мк.
В CVAVR put(char a) для отправки символа, для отправки строчек puts(char a[])